<?php
// +----------------------------------------------------------------------
// | KITEGO-Admin「开箱即用」「人人全栈」
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2024 https://www.kitego.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed KITEGO并不是自由软件，未经许可不能去掉KITEGO相关版权
// +----------------------------------------------------------------------
// | Author: KITEGO Team <bd@kitego.cn>
// +----------------------------------------------------------------------

namespace kitego\base;

use think\App;
use think\exception\ValidateException;
use think\Request;
use think\Validate;

/**
 * 控制器基础类
 */
abstract class BaseController
{

    public array $safeAction = []; // 安全方法

    public array $params = []; // 接口参数

    /**
     * Request实例
     * @var Request
     */
    protected $request;

    /**
     * 应用实例
     * @var \think\App
     */
    protected $app;

    /**
     * 是否批量验证
     * @var bool
     */
    protected $batchValidate = false;

    /**
     * 控制器中间件
     * @var array
     */
    protected $middleware = [];

    /**
     * 构造方法
     * @access public
     * @param App $app 应用对象
     */
    public function __construct(App $app)
    {
        $this->app = $app;
        $this->request = $this->app->request;

        // 控制器初始化
        $this->initialize();
    }

    // 初始化
    protected function initialize()
    {
        $this->params = req_decode();
    }

    /**
     * 验证数据
     * @access protected
     * @param array $data 数据
     * @param string|array $validate 验证器名或者验证规则数组
     * @param array $message 提示信息
     * @param bool $batch 是否批量验证
     * @return array|string|true
     * @throws ValidateException
     */
    protected function validate(array $data, string|array $validate, array $message = [], bool $batch = false)
    {
        if (is_array($validate)) {
            $v = new Validate();
            $v->rule($validate);
        } else {
            if (strpos($validate, '.')) {
                // 支持场景
                [$validate, $scene] = explode('.', $validate);
            }
            $class = false !== strpos($validate, '\\') ? $validate : $this->app->parseClass('validate', $validate);
            $v = new $class();
            if (!empty($scene)) {
                $v->scene($scene);
            }
        }

        $v->message($message);

        // 是否批量验证
        if ($batch || $this->batchValidate) {
            $v->batch(true);
        }

        return $v->failException(true)->check($data);
    }

    /**
     * 检测当前请求的方法是否需要跳过鉴权验证
     *
     * 基于控制器中定义的$safeAction属性判断当前操作是否在免鉴权名单中。
     * $safeAction的配置规则：
     * - ['all']：当前控制器下所有方法均免鉴权
     * - 空数组[]：当前控制器下所有方法均需鉴权
     * - 具体方法名数组（如['test']）：仅数组中指定的方法免鉴权
     *
     * @return bool true表示当前方法免鉴权，false表示需要鉴权
     */
    public function checkSafeAction(): bool
    {
        // 获取当前控制器定义的免鉴权方法配置
        $safeAction = $this->safeAction;

        // 获取当前请求的方法名
        $action = request()->action();

        // 若未配置免鉴权方法，则所有方法均需鉴权
        if (empty($safeAction)) {
            return false;
        }

        // 两种情况需鉴权：
        // 1. 当前方法不在免鉴权列表中
        // 2. 未配置"all"（即不允许所有方法免鉴权）
        if (!in_array($action, $safeAction) && !in_array('all', $safeAction)) {
            return false;
        }

        // 其余情况均免鉴权
        return true;
    }
}
